/**
 ******************************************************************************
 * @file    i2s.c
 * @author  hyseim software Team
 * @date    18-Aug-2023
 * @brief   This file provides all the tmp functions.
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2020 Hyseim. Co., Ltd.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "i2s.h"
#include "common.h"


/** @addtogroup IM110GW_Driver
 * @{
 */

/** @defgroup I2S
 * @brief I2S driver modules
 * @{
 */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/** @defgroup I2S_Private_Functions
  * @{
  */

/**
 * @brief  Deinitializes the I2S peripheral registers to their default reset values.
 * @return None
 */
void I2S_DeInit(void)
{
    im_write32((CRG_BASE + 0x118), (0x1 << 12) | ((0x1 << 12) << 16));
    im_write32((CRG_BASE + 0x118), (0X0 << 12) | ((0x1 << 12) << 16));
}

/**
 * @brief  Enables or disables the specified I2S peripheral.
 * @param  NewState: new state of the I2S peripheral.
 *         This parameter can be: ENABLE or DISABLE.
 * @return None
 */
void I2S_Cmd(FunctionalState_t NewState)
{
    if (NewState != DISABLE) {
        I2S->IER = 0x01;
    }
    else {
        I2S->IER = 0x00;
    }
}

/**
 * @brief  Enables or disables the I2S receiver block.
 * @param  NewState: new state of the receiver block.
 *         This parameter can be: ENABLE or DISABLE.
 * @return None
 */
void I2S_ReceiverCmd(FunctionalState_t NewState)
{
    if (NewState != DISABLE) {
        I2S->IRER = 0x01;
    }
    else {
        I2S->IRER = 0x00;
    }
}

/**
 * @brief  Enables or disables the I2S transmitter block.
 * @param  NewState: new state of the transmitter block.
 *         This parameter can be: ENABLE or DISABLE.
 * @return None
 */
void I2S_TransmitterCmd(FunctionalState_t NewState)
{
    if (NewState != DISABLE) {
        I2S->ITER = 0x01;
    }
    else {
        I2S->ITER = 0x00;
    }
}

/**
 * @brief  Configures I2S Clock Generation block.
 * @param  I2S_WordSelectSize: specifies the number of sclk cycles for which the 
 *         word select line stays in the left or right sample mode.
 *          This parameter can be one of the following values:
 *           @arg @ref I2S_WordSelectSize_16
 *           @arg @ref I2S_WordSelectSize_24
 *           @arg @ref I2S_WordSelectSize_32
 * @param  I2S_SclkGate: specifies the gating of sclk.
 *          This parameter can be one of the following values:
 *           @arg @ref I2S_SclkGate_None
 *           @arg @ref I2S_SclkGate_12
 *           @arg @ref I2S_SclkGate_16
 *           @arg @ref I2S_SclkGate_20
 *           @arg @ref I2S_SclkGate_24
 * @return None
 */
void I2S_ClockConfig(uint32_t I2S_WordSelectSize, uint32_t I2S_SclkGate)
{
    I2S->CCR = I2S_WordSelectSize | I2S_SclkGate;
}

/**
 * @brief  Enables or disables the I2S clock generation block.
 * @param  NewState: new state of the clock generation block.
 *         This parameter can be: ENABLE or DISABLE.
 * @return None
 */
void I2S_ClockCmd(FunctionalState_t NewState)
{
    if (NewState != DISABLE) {
        I2S->CER = 0x01;
    }
    else {
        I2S->CER = 0x00;
    }
}

/**
 * @brief  Flushes all the RX FIFOs.
 * @return None
 */
void I2S_ReceiverFIFOFlush(void)
{
    I2S->RXFFR = 0x01;
}

/**
 * @brief  Flushes all the TX FIFOs.
 * @return None
 */
void I2S_TransmitterFIFOFlush(void)
{
    I2S->TXFFR = 0x01;
}

/**
 * @brief  Read the left stereo data from Rx FIFO.
 * @return The left stereo data.
 */
uint32_t I2S_Channel_ReadLeftData(void)
{
    return I2S->LRBR;
}

/**
 * @brief  Read the right stereo data from Rx FIFO.
 * @return The right stereo data.
 */
uint32_t I2S_Channel_ReadRightData(void)
{
    return I2S->RRBR;
}

/**
 * @brief  Write the left stereo data to Tx FIFO.
 * @param  LeftData: The left stereo data to write.
 * @return None
 */
void I2S_Channel_WriteLeftData(uint32_t LeftData)
{
    I2S->LTHR = LeftData;
}

/**
 * @brief  Write the right stereo data to Tx FIFO.
 * @param  RightData: The right stereo data to write.
 * @return None
 */
void I2S_Channel_WriteRightData(uint32_t RightData)
{
    I2S->RTHR = RightData;
}

/**
 * @brief  Enables or disables the receive channel.
 * @param  NewState: new state of the receive channel.
 *         This parameter can be: ENABLE or DISABLE.
 * @return None
 */
void I2S_Channel_ReceiveCmd(FunctionalState_t NewState)
{
    if (NewState != DISABLE) {
        I2S->RER = 0x01;
    }
    else {
        I2S->RER = 0x00;
    }
}

/**
 * @brief  Enables or disables the transmit channel.
 * @param  NewState: new state of the transmit channel.
 *         This parameter can be: ENABLE or DISABLE.
 * @return None
 */
void I2S_Channel_TransmitCmd(FunctionalState_t NewState)
{
    if (NewState != DISABLE) {
        I2S->TER = 0x01;
    }
    else {
        I2S->TER = 0x00;
    }
}

/**
 * @brief  Configures the desired data resolution of the receiver.
 * @param  I2S_DataFormat: specifies the desired data resolution.
 *          This parameter can be one of the following values:
 *           @arg @ref I2S_DataFormat_Ignore
 *           @arg @ref I2S_DataFormat_12b
 *           @arg @ref I2S_DataFormat_16b
 *           @arg @ref I2S_DataFormat_20b
 *           @arg @ref I2S_DataFormat_24b
 *           @arg @ref I2S_DataFormat_32b
 * @return None
 */
void I2S_Channel_ReceiveConfig(uint32_t I2S_DataFormat)
{
    I2S->RCR = I2S_DataFormat;
}

/**
 * @brief  Configures the data resolution of the transmitter.
 * @param  I2S_DataFormat: specifies the data resolution.
 *          This parameter can be one of the following values:
 *           @arg @ref I2S_DataFormat_Ignore
 *           @arg @ref I2S_DataFormat_12b
 *           @arg @ref I2S_DataFormat_16b
 *           @arg @ref I2S_DataFormat_20b
 *           @arg @ref I2S_DataFormat_24b
 *           @arg @ref I2S_DataFormat_32b
 * @return None
 */
void I2S_Channel_TransmitConfig(uint32_t I2S_DataFormat)
{
    I2S->TCR = I2S_DataFormat;
}

/**
 * @brief  Enables or disables the specified I2S interrupts.
 * @param  I2S_IT: specifies the I2S interrupt source to be enabled or disabled. 
 *         This parameter can be a combination of the following values:
 *         @arg @ref I2S_IT_RXDA: RX FIFO Data Available interrupt.
 *         @arg @ref I2S_IT_RXFO: RX FIFO Overrun interrupt.
 *         @arg @ref I2S_IT_TXFE: TX FIFO Empty interrupt.
 *         @arg @ref I2S_IT_TXFO: TX FIFO Overrun interrupt.
 * @param  NewState: new state of the specified I2S interrupt.
 *         This parameter can be: ENABLE or DISABLE.
 * @return None.
 */
void I2S_Channel_ITConfig(uint8_t I2S_IT, FunctionalState_t NewState)
{
    if (NewState != DISABLE) {
        I2S->IMR &= ~I2S_IT;
    }
    else {
        I2S->IMR |= I2S_IT;
    }
}

/**
 * @brief  Checks whether the specified I2S interrupt has occurred or not.
 * @param  I2S_IT: specifies the I2S interrupt source to check.
 *         This parameter can be one of the following values:
 *         @arg @ref I2S_IT_RXDA: RX FIFO Data Available interrupt.
 *         @arg @ref I2S_IT_RXFO: RX FIFO Overrun interrupt.
 *         @arg @ref I2S_IT_TXFE: TX FIFO Empty interrupt.
 *         @arg @ref I2S_IT_TXFO: TX FIFO Overrun interrupt.
 * @return The new state of I2S_IT (SET or RESET).
 */
ITStatus_t I2S_Channel_GetITStatus(uint8_t I2S_IT)
{
    ITStatus_t bitstatus = RESET;

    if (I2S->ISR & I2S_IT) {
        bitstatus = SET;
    }
    else {
        bitstatus = RESET;
    }
    return bitstatus;
}

/**
 * @brief  Clears the I2S interrupt pending bits.
 * @param  I2S_IT: specifies the interrupt pending bit to clear.
 *         This parameter can be a combination of the following values:
 *         @arg @ref I2S_IT_RXFO: RX FIFO Overrun interrupt.
 *         @arg @ref I2S_IT_TXFO: TX FIFO Overrun interrupt.
 * @return None.
 */
void I2S_Channel_ClearITPendingBit(uint8_t I2S_IT)
{
    if (I2S_IT & I2S_IT_RXFO) {
        (void)I2S->ROR;
    }

    if (I2S_IT & I2S_IT_TXFO) {
        (void)I2S->TOR;
    }
}

/**
 * @brief  Configures the Rx FIFO threshold.
 * @param  Threshold: The Rx FIFO threshold to set.
 * @note   The RX FIFO Data Available interrupt will trigger when the level > Threshold.
 * @return None.
 */
void I2S_Channel_ReceiveFIFOConfig(uint8_t Threshold)
{
    I2S->RFCR = Threshold;
}

/**
 * @brief  Configures the Tx FIFO threshold.
 * @param  Threshold: The Tx FIFO threshold to set.
 * @note   The TX FIFO Empty interrupt will trigger when the level <= Threshold.
 * @return None.
 */
void I2S_Channel_TransmitFIFOConfig(uint8_t Threshold)
{
    I2S->TFCR = Threshold;
}

/**
 * @brief  Flushes the corresponding RX FIFO.
 * @return None
 */
void I2S_Channel_ReceiveFIFOFlush(void)
{
    I2S->RFF = 0x01;
}

/**
 * @brief  Flushes the corresponding TX FIFO.
 * @return None
 */
void I2S_Channel_TransmitFIFOFlush(void)
{
    I2S->TFF = 0x01;
}

/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */
